﻿using Kinlo.Entitys;
using Kinlo.MESDocking;
using NPOI.OpenXmlFormats;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Interop;
using UIWindows.Commands;
using UIWindows.Domains;
using UIWindows.GlobalStatics;
using UIWindows.Models;
using UIWindows.Tools;
using UIWindows.Tools.Helper;
using UIWindows.UserControls;
using UIWindows.Views;
using XingLucifer.Devices;
using XingLucifer.IBase.Enums;
using static System.Windows.Forms.VisualStyles.VisualStyleElement.StartPanel;

namespace UIWindows.ViewModels
{
    public class ManualWeightViewModel : ViewModelBase
    {
        #region 双向绑定
        private string _barcode;
        /// <summary>
        /// 电池条码
        /// </summary>
        public string Barcode
        {
            get { return _barcode; }
            set { SetProperty(ref _barcode, value); }
        }
        private string _strartTime;
        /// <summary>
        /// 开始时间
        /// </summary>
        public string StrartTime
        {
            get { return _strartTime; }
            set { SetProperty(ref _strartTime, value); }
        }
        private double _BeforeWeighing;
        /// <summary>
        /// 干重重
        /// </summary>
        public double BeforeWeighing
        {
            get { return _BeforeWeighing; }
            set { SetProperty(ref _BeforeWeighing, value); }
        }
        private double _afterWeighing;
        /// <summary>
        /// 后称重
        /// </summary>
        public double AfterWeighing
        {
            get { return _afterWeighing; }
            set { SetProperty(ref _afterWeighing, value); }
        }
        private double _CurrentWeight;
        /// <summary>
        /// 当前重量
        /// </summary>
        public double CurrentWeight
        {
            get { return _CurrentWeight; }
            set { SetProperty(ref _CurrentWeight, value); }
        }
        //  private double _InjectionVolume;
        /// <summary>
        /// 注液量
        /// </summary>
        //public double InjectionVolume
        //{
        //    get { return _InjectionVolume; }
        //    set { SetProperty(ref _InjectionVolume, value); }
        //}
        //private double _refillInjectionVolume;
        /// <summary>
        /// 补液量
        /// </summary>
        //public double RefillInjectionVolume
        //{
        //    get { return _refillInjectionVolume; }
        //    set { SetProperty(ref _refillInjectionVolume, value); }
        //}
        private double _actualTotalInjectionVolume;
        /// <summary>
        /// 保液量
        /// </summary>
        public double ActualTotalInjectionVolume
        {
            get { return _actualTotalInjectionVolume; }
            set { SetProperty(ref _actualTotalInjectionVolume, value); }
        }
        private string _rangeFluidRate = string.Empty;
        /// <summary>
        /// 保液量范围
        /// </summary>
        public string RangeFluidRate
        {
            get { return _rangeFluidRate; }
            set { SetProperty(ref _rangeFluidRate, value); }
        }
        private double _totalInjectionVolumeDeviationValue;
        /// <summary>
        /// 保液量偏差
        /// </summary>
        public double TotalInjectionVolumeDeviationValue
        {
            get { return _totalInjectionVolumeDeviationValue; }
            set { SetProperty(ref _totalInjectionVolumeDeviationValue, value); }
        }

        private ResultTypes _leakResult;
        /// <summary>
        /// 测漏结果
        /// </summary>
        public ResultTypes LeakResult
        {
            get { return _leakResult; }
            set { SetProperty(ref _leakResult, value); }
        }
        private ResultTypes _Results;
        /// <summary>
        /// 结果
        /// </summary>
        public ResultTypes Results
        {
            get { return _Results; }
            set { SetProperty(ref _Results, value); }
        }
        private ResultTypes _TotalResult;
        /// <summary>
        /// 总结果
        /// </summary>
        public ResultTypes TotalResult
        {
            get { return _TotalResult; }
            set { SetProperty(ref _TotalResult, value); }
        }

        private string _msg = string.Empty;
        /// <summary>
        /// 提示消息
        /// </summary>
        public string Msg
        {
            get { return _msg; }
            set { SetProperty(ref _msg, value); }
        }
        #endregion

        private TemporaryStatic _temporaryStatic;
        private ParameterStatic _parameterStatic;
        private SystemConfigStatic _systemConfigStatic;
        private DeviceConfigStatic _deviceConfigStatic;
        public ManualWeightViewModel(TemporaryStatic temporaryStatic, ParameterStatic parameterStatic, SystemConfigStatic systemConfigStatic, DeviceConfigStatic deviceConfigStatic)
        {
            Msg = string.Empty;
            KeyboardHook.RegistrationListening(24, GetBarCode);
            _temporaryStatic = temporaryStatic;
            _parameterStatic = parameterStatic;
            _systemConfigStatic = systemConfigStatic;
            _deviceConfigStatic = deviceConfigStatic;

        }
        /// <summary>
        /// 扫码回调
        /// </summary>
        /// <param name="barcode"></param>
        public void GetBarCode(string barcode)
        {
            LogAdd($"[手持扫码枪] 返回：{barcode}");
            barcode = System.Text.RegularExpressions.Regex.Match(barcode, _systemConfigStatic.SCM.BarcodeRules, System.Text.RegularExpressions.RegexOptions.Compiled).Value;
            LogAdd($"[手持扫码枪] 校验后：{barcode}");
            if (!string.IsNullOrEmpty(barcode))
            {
                
                WeighingBusiness(barcode).ConfigureAwait(false);
            }
            else
            {
                LogAdd("[手工补液称] 条码不符合规则!");
            }
        }
        private async Task WeighingBusiness(string barcode)
        {
            await Task.Run(async () =>
            {
                DateTime dateTime = DateTime.Now;
                StrartTime = dateTime.ToString("HH:mm:ss");
                Models.Devices.DeviceClientModel devicemodel = _deviceConfigStatic.DeviceList.FirstOrDefault(x => x.TaskType == TaskTypes.手工补液称);

                if (devicemodel == null)
                {
                    LogAdd("[手工补液称] 未找到补液称!!!请添加补液称设备。");
                    return Task.CompletedTask;
                }
                ProductionData? entity = _temporaryStatic.EntityCache.FirstOrDefault(x => x.BarCode == barcode && (x.SnowflakeId == _temporaryStatic.EntityCache.Max(x => x.SnowflakeId)));
                if (entity == null)
                {
                    LogAdd($"[手工补液称] 实体缓存查询不到==>[{barcode}]，转到数据库查询");
                    entity = dateTime.GetNewEntity(TaskTypes.补液称.ToString(), barcode);
                }
                else
                {
                    ProductionData.Meta.TableName = entity.Items["TableName"].ToString();
                }
                if (entity == null)
                {
                    LogAdd($"[手工补液称] 数据库找不到条码：[{barcode}]");
                    return Task.CompletedTask;
                }
                LogAdd($"[手工补液称] 称重 ID：[{entity.SnowflakeId}] 条码：[{entity.BarCode}]");

                Barcode = entity.BarCode;
                BeforeWeighing = entity.NetWeight;
                AfterWeighing = entity.AfterWeighing;
                RangeFluidRate = entity.RangeFluidRate;
                LeakResult = entity.LeakResult;
                CurrentWeight = GetWeiging(devicemodel) ?? 0;
                if (CurrentWeight == 0)
                {
                    LogAdd("未获取到稳定值!!!请检查硬件是否正常。");
                    return Task.CompletedTask;
                }
                entity.RehydrationWeighing = CurrentWeight;
                entity.TimeRehydrationWeighing = dateTime.GetJSTimeUtc();

                entity.FluidRateReplenish = Math.Round(entity.RehydrationWeighing - entity.AfterWeighing, 1, MidpointRounding.AwayFromZero);
                ActualTotalInjectionVolume = entity.ActualTotalInjectionVolume = Math.Round(entity.RehydrationWeighing - entity.NetWeight, 2, MidpointRounding.AwayFromZero);
                if (_systemConfigStatic.SCM.MainDeviceType == MainDeviceTypeEnum.一次注液)
                    entity.OneAfterWeighing = entity.RehydrationWeighing;
                Results = entity.ResultRefillWeighing = InjRange_Check(entity, 2);
                if (entity.ResultRefillWeighing != ResultTypes.合格 && entity.ResultTotal == ResultTypes._)
                    entity.ResultTotal = entity.ResultRefillWeighing;

                if (entity.ResultRefillWeighing != ResultTypes.合格 &&
                entity.ResultRefillWeighing != entity.ResultRefillWeighing &&
                entity.ResultTotal != ResultTypes._)
                    LeakResult = entity.ResultTotal;
                try
                {
                    entity.Update();
                    await Task.Run(() =>
                    {
                        Application.Current.Dispatcher.Invoke(() =>
                        {

                            StringBuilder _msgOutput = new StringBuilder();
                            _msgOutput.Append("[出站错误] ");
                            bool _isHaveErr = false;
                            var _deviceConfigStatic = Domains.ObjectContainer.ResolveSingleton<GlobalStatics.DeviceConfigStatic>();
                            var _userConfigStatic = Domains.ObjectContainer.ResolveSingleton<GlobalStatics.UserConfigStatic>();
                            var _systemConfig = Domains.ObjectContainer.ResolveSingleton<GlobalStatics.SystemConfigStatic>();
                            var _homeStatic = Domains.ObjectContainer.ResolveSingleton<GlobalStatics.HomeStatic>();
                            var _parameterStatic = Domains.ObjectContainer.ResolveSingleton<GlobalStatics.ParameterStatic>();
                            var _mesParameterStatic = Domains.ObjectContainer.ResolveSingleton<GlobalStatics.MesParameterStatic>();
                            var _temporaryStatic = Domains.ObjectContainer.ResolveSingleton<GlobalStatics.TemporaryStatic>();
                            Test test = new Test(_deviceConfigStatic, _systemConfig, _userConfigStatic, _parameterStatic, _temporaryStatic, _homeStatic, _mesParameterStatic);

                            IMESInteraction _interactionOutput = new ProduceOpenAddInterface(DialogLogHelper.MesLog, DialogLogHelper.MESDialog);
                            bool isok = true;

                            string ngType = "";
                            if (entity.ResultTotal!= ResultTypes._&& entity.ResultTotal != ResultTypes.合格)
                            {
                                ngType= entity.ResultTotal.ToString();
                            }
                            
                            if (test.BatteryOutboundDataUpload(_interactionOutput, entity, isok, ngType) != ResultTypes.合格)
                            {
                                _isHaveErr = false;

                            }
                            if (_isHaveErr)
                            {
                                LogAdd("[手工补液出站上传MES]上传失败，但有错误，详情请查看日志!!!");
                                //"[出站上传MES]上传完成，但有错误，详情请查看日志!!!".MessageDialogs(MessageLevelType.警告, false, PopUpTypes.Global);
                            }
                            else
                                LogAdd("[手工补液出站上传MES]上传成功!!!");
                            //"[出站上传MES]上传成功!!!".MessageDialogs(MessageLevelType.成功, false, PopUpTypes.Global);
                        });
                    });

                    LogAdd("[手工补液称] 更新数据库成功！");
                }
                catch (Exception e)
                {
                    LogAdd("[手工补液称] 更新数据库失败...");
                }

                await Application.Current.Dispatcher.BeginInvoke(new Action(() => { Msg = string.Empty; }));
                return Task.CompletedTask;
            });
        }
        public double? GetWeiging(Models.Devices.DeviceClientModel device)
        {
            try
            {
                Stopwatch stopwatch = new Stopwatch();
                stopwatch.Restart();
                double? before_weighing = null, after_weighing = null;
                while (stopwatch.ElapsedMilliseconds < _systemConfigStatic.SCM.WeighingTimeout)
                {
                    before_weighing = device.Communication.ReadSingle<double>(0, 0);
                    if (before_weighing != null)
                    {
                        LogAdd($"-[手工补液称] 获取到重量 ==> {before_weighing} g");
                        if (after_weighing != null)
                        {
                            double difference = Math.Round((double)(before_weighing - after_weighing), 1, MidpointRounding.AwayFromZero);
                            if (difference >= -0.3 && difference <= 0.3)
                            {
                                LogAdd($"-[手工补液称] 获取到的稳定值 ==> {before_weighing} g");
                                stopwatch.Stop();
                                return before_weighing;
                            }
                        }
                        after_weighing = before_weighing;
                    }
                    Thread.Sleep(500);
                }
                stopwatch.Stop();
            }
            catch (Exception ex)
            {

                LogAdd($"[手工补液称] 异常：{ex}");
            }

            return default;
        }


        /// <summary>
        /// 注液范围检查
        /// </summary>
        /// <param name="entity"></param>
        /// <param name="Index">1:后称，2：补液称</param>
        /// <returns></returns>
        public ResultTypes InjRange_Check(ProductionData entity, int index)
        {
            string[] range = entity.RangeFluidRate.Split('-');
            double down_inj = Convert.ToDouble(range[0]);
            double standard = Convert.ToDouble(range[1]);
            double up_inj = Convert.ToDouble(range[2]);

            range = entity.RangeAfterWeighing.Split('-');
            double down_weiging = Convert.ToDouble(range[0]);
            double up_weiging = Convert.ToDouble(range[1]);

            TotalInjectionVolumeDeviationValue = entity.TotalInjectionVolumeDeviationValue = Math.Round(entity.ActualTotalInjectionVolume - standard, 2, MidpointRounding.AwayFromZero);

            var weighting = index == 1 ? entity.AfterWeighing : entity.RehydrationWeighing;
            ResultTypes types = (weighting, entity.ActualTotalInjectionVolume) switch
            {
                var k when k.weighting <= up_weiging && k.weighting >= down_weiging && k.ActualTotalInjectionVolume <= up_inj && k.ActualTotalInjectionVolume >= down_inj => ResultTypes.合格,
                var k when k.weighting > up_weiging => ResultTypes.称重偏重,
                var k when k.weighting < down_weiging => ResultTypes.称重偏轻,
                var k when k.ActualTotalInjectionVolume > up_inj => ResultTypes.注液量偏多,
                var k when k.ActualTotalInjectionVolume < down_inj => ResultTypes.注液量偏少,
                _ => ResultTypes.不合格,
            };

            if (!_parameterStatic.DecideParameter.EnableAfterInjection && (types == ResultTypes.称重偏轻 || types == ResultTypes.称重偏重))
            {
                LogAdd($"请注意!!![{entity.BarCode}] 未启用后称重检查==>>强制合格");
                return ResultTypes.合格;
            }
            if (!_parameterStatic.DecideParameter.EnableLiquidInjectionRange && (types == ResultTypes.注液量偏多 || types == ResultTypes.注液量偏少))
            {
                LogAdd($"请注意!!![{entity.BarCode}] 未启用注液量检查==>>强制合格");
                return ResultTypes.合格;
            }
            return types;
        }

        public DelegateCommand Closing => new DelegateCommand(() =>
        {
            KeyboardHook.UninstallationListening(24);
        });
        private void LogAdd(string str, MessageLevelType levelType = MessageLevelType.信息)
        {
            try
            {
                string errMsg = $"{DateTime.Now:HH:mm:ss} ==> {str}";
                UIWindows.Tools.Helper.DialogLogHelper.RunLog(errMsg, levelType);
                Application.Current.Dispatcher.Invoke(new Action(() => { Msg = errMsg; }));
            }
            catch (Exception ex)
            {
            }
        }
    }
}
